﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace _80X_CG_Frame.Protocols
{
    public class Camera
    {
        private TcpClient client;
        private NetworkStream ns;
        const int maxBufferSize = 4096;
        public Camera(TcpClient client)
        {
            this.client = client;
            ns = this.client.GetStream();
            ns.ReadTimeout = 100;
        }

        public string Capture(int id, int mode, ref string result)
        {
            //string cmd = "00000000000602060001" + id.ToString("X2") + mode.ToString("X2");
            string cmd = "00000000000602031400000a";
            string msg = Transmit(cmd, ref result);

            return msg;
        }

        /// <summary>
        /// 选择相机任务,可直接切换
        /// </summary>
        /// <param name="id"></param>
        /// <param name="mode"></param>
        /// <param name="result"></param>
        /// <returns></returns>
        public string SelectTask(int id, int mode, ref string result)
        {
            string cmd = "00000000000602060003" + id.ToString("X2") + mode.ToString("X2");
            //00 00 00 00 00 06 02 06 00 03 00 01
            string msg = Transmit(cmd, ref result);

            return msg;
        }

        public string CancelTask(int id, int mode, ref string result)
        {
            string cmd = "00000000000602060004" + id.ToString("X2") + mode.ToString("X2");
            string msg = Transmit(cmd, ref result);

            return msg;
        }

        public string ClearTask(int id, int mode, ref string result)
        {
            string cmd = "00000000000602060007" + id.ToString("X2") + mode.ToString("X2");
            string msg = Transmit(cmd, ref result);

            return msg;
        }

        public string RunningStatus(ref string result)
        {
            string cmd = "000000000006020110000001";
            string msg = Transmit(cmd, ref result);

            return msg;
        }

        public string BusyStatus(string Adress, ref string result)
        {
            //00 00 00 00 00 06 02 01 10 11 00 01
            string cmd = "0000000000060201" + Adress + "0001";
            string msg = Transmit(cmd, ref result);

            return msg;
        }

        public string HasResult(ref string result)
        {
            string cmd = "000000000006020110020001";
            string msg = Transmit(cmd, ref result);

            return msg;
        }

        public string TaskManage(ref string result)
        {
            string cmd = "00000000000602031100XXXX";
            string msg = Transmit(cmd, ref result);

            return msg;
        }

        public string TaskRun(ref string result)
        {
            string cmd = "00000000000602031100XXXX";
            string msg = Transmit(cmd, ref result);

            return msg;
        }

        public string Calibrate(ref string result)
        {
            string cmd = "00000000000602031140XXXX";
            string msg = Transmit(cmd, ref result);

            return msg;
        }

        /// <summary>
        /// 取相机结果
        /// </summary>
        /// <param name="start_address"></param>
        /// <param name="length"></param>
        /// <param name="result"></param>
        /// <returns></returns>
        public string GetResult(string start_address, int length, ref string result)
        {
            string cmd = "0000000000060203" + start_address + length.ToString("X4");
            //string cmd = "00 00 00 00 00 06 02 03 14 00 00 0a";
            string msg = Transmit(cmd, ref result);

            return msg;
        }

        public string GetTaskStatus(int id, ref List<string> result)
        {
            string block = Camera.BlockAddress[id];
            string cmd = "0000000000060203" + block + "0020";
            string result_str = "";
            string msg = Transmit(cmd, ref result_str);
            if (result_str != "")
            {
                result.Add(result_str.Substring(24, 2));
                result.Add(result_str.Substring(50, 16));
            }
            return msg;
        }


        private string Transmit(string cmd, ref string result)
        {
            byte[] byteSend = new byte[maxBufferSize];
            byte[] byteReceive = new byte[maxBufferSize];

            lock (client)
            {
                try
                {
                    //byteSend = Encoding.ASCII.GetBytes(cmd);
                    byteSend = ToByteArray(cmd);
                    //byteSend = Encoding.BigEndianUnicode.GetBytes(cmd);
                    ns.Write(byteSend, 0, byteSend.Length);
                    ns.Flush();

                    if (ns.CanRead)
                    {
                        do
                        {
                            int len = ns.Read(byteReceive, 0, maxBufferSize);

                            if (len > 0)
                            {
                                result = ByteArrayToStr(byteReceive, len);
                                //result = Encoding.ASCII.GetString(byteReceive, 0, len);
                            }
                            else
                            {
                                DisConnect();
                            }
                        } while (ns.DataAvailable);
                    }
                    else
                    {
                        DisConnect();
                    }
                }
                catch (Exception ex)
                {
                    DisConnect();
                    return ex.ToString();
                }

            }
            return "";
        }
        private void DisConnect()
        {
            if (ns != null)
                ns.Close();
            if (client.Client != null)
                client.Client.Close();
            if(client != null)
                client.Close();
            //NotifyPropertyChanged("IsConnect");
        }
        private string ToByteLength(int length)
        {
            return length.ToString("X4");
        }
        private byte[] ToByteArray(string str)
        {
            List<byte> bytes = new List<byte>();
            for (int i = 0; i < str.Length; i += 2)
            {
                bytes.Add(Convert.ToByte(str.Substring(i, 2), 16));
            }
            return bytes.ToArray();
        }
        private string ByteArrayToStr(byte[] bytes, int length)
        {
            var str = "";
            for (int i = 0; i < length; i++)
            {
                str += bytes[i].ToString("X2");
            }
            return str;
        }

        /// <summary>
        /// 取相机Arc(Circle)Tool 圆与圆弧结果
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public string[] ParseCircleData(string str)
        {
            List<string> result = new List<string>();
            //string result_str = "";
            result.Add(ToDouble(str.Substring(22, 8)));//x
            result.Add(ToDouble(str.Substring(30, 8)));//y
            result.Add(ToDouble(str.Substring(38, 8)));//z

            return result.ToArray();
        }

        /// <summary>
        /// ContourMatch轮廓匹配结果
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public string[] ParseContourData(string str)
        {
            List<string> result = new List<string>();
            //string result_str = "";
            //start 23
            result.Add(ToDouble(str.Substring(22, 8)));//x
            result.Add(ToDouble(str.Substring(30, 8)));//y
            result.Add(ToDouble(str.Substring(38, 8)));//z
            result.Add(ToDouble(str.Substring(58, 8)));//r

            return result.ToArray();
        }
        public string[] ParseContourMatchData(string str)
        {
            List<string> result = new List<string>();
            //string result_str = "";
            //start 23
            result.Add(ToDouble(str.Substring(50, 8)));//match score
            result.Add(ToDouble(str.Substring(58, 8)));//rotation

            return result.ToArray();
        }
        /// <summary>
        /// BlobLocator（bolb定位器）
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public string[] ParseBlobData(string str)
        {
            List<string> result = new List<string>();
            //string result_str = "";
            //start 23
           // result.Add(ToDouble(str.Substring(18, 4)));//result
            result.Add(ToDouble(str.Substring(22, 8)));//x
            result.Add(ToDouble(str.Substring(30, 8)));//y
            //result.Add(ToDouble(str.Substring(38, 8)));//z

            return result.ToArray();
        }

        public string ParseCameraBusy(string str)
        {
            string result_str = str.Substring(18, 2);
            return result_str;
        }
        public string[] ParseStatusBlobData(string str)
        {
            List<string> result = new List<string>();
            //string result_str = "";
            //start 23
            result.Add(str.Substring(20, 2));//result
            result.Add(ToDouble(str.Substring(22, 8)));//x
            result.Add(ToDouble(str.Substring(30, 8)));//y
            //result.Add(ToDouble(str.Substring(38, 8)));//z

            return result.ToArray();
        }


        /// <summary>
        /// BlobLocator（bolb定位器）取SubBlob
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public string[] ParsesSubBlobData(string str)
        {
            List<string> result = new List<string>();
            //string result_str = "";
            //start 22
            result.Add(ToDouble(str.Substring(18+(4*22), 8)));//x1
            result.Add(ToDouble(str.Substring(18+(4*24), 8)));//y1

            result.Add(ToDouble(str.Substring(18 + (4 * 34), 8)));//x2
            result.Add(ToDouble(str.Substring(18 + (4 * 36), 8)));//y2
            //result.Add(ToDouble(str.Substring(38, 8)));//z

            return result.ToArray();
        }

        public string[] ParseEdgeData(string str)
        {
            List<string> result = new List<string>();
            //string result_str = "";
            //start 23
            result.Add(ToDouble(str.Substring(54, 8)));//Angle


            return result.ToArray();
        }
        public string[] ParseObjectData(string str)
        {
            List<string> result = new List<string>();
            //string result_str = "";
            //start 23

            result.Add(ToDouble(str.Substring(22, 8)));//x
            result.Add(ToDouble(str.Substring(30, 8)));//y
            result.Add(ToDouble(str.Substring(38, 8)));//z
            result.Add(ToDouble(str.Substring(54, 8)));//Angle


            return result.ToArray();
        }
        private string ToUInt(string str)
        {
            if (str.Length == 4)
            {
                return Convert.ToUInt16(str, 16).ToString();
            }
            else if (str.Length == 8)
            {
                return Convert.ToInt32(str, 16).ToString();
            }
            return "0";
        }
        private string ToDouble(string str)
        {
            if (str.Length == 8)
            {
                //var result = Convert.ToDouble(str);
                var result = Convert.ToInt32(str, 16);
                
                return (result / 1000.0).ToString();
            }
            return "0";
        }

        /// <summary>
        /// 地址增加偏移量
        /// </summary>
        /// <param name="address"></param>
        /// <param name="offset"></param>
        /// <returns></returns>
        public static string AddressOffset(string address, int offset)
        {
            return (Convert.ToInt32(address, 16) + offset).ToString("X4");
        }

        public static Dictionary<int, string> Address = new Dictionary<int, string>()
        {
            {0,"1a00"},
            {1,"2800"},
            {2,"3600"},
            {3,"4400"},
            {4,"5200"},
            {5,"6000"},
            {6,"6e00"},
            {7,"7c00"},
            {8,"8a00"},
            {9,"9800"},
            {10,"a600"},
            {11,"b400"},
            {12,"c200"},
            {13,"d000"},
            {14,"de00"},
            {15,"ec00"}
        };

        public static Dictionary<int, string> BlockAddress = new Dictionary<int, string>()
        {
            {0,"1300"},
            {1,"1340"},
            {2,"1380"},
            {3,"13c0"},
            {4,"1400"},
            {5,"1440"},
            {6,"1480"}
        };

        public static Dictionary<int, string> CoilRegisterAddress = new Dictionary<int, string>()
        {
            //真正的地址由来 ，coil相机地址 + offset 
            {0,"1011"},
            {1,"1031"},
            {2,"1051"},
            {3,"1071"},
            {4,"1091"},
            {5,"10B1"},
            {6,"10D1"}
        };
    }

    public enum Result
    {
        None,
        NotLocate,
        Failed,
        Passed
    }
}
